%{
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <float.h>

//constantes
#define CANT_ESTADOS 30
#define CANT_CARACTERES 26
#define CANT_RESERV 27

#define MAX 31 //30 + \0

#define TIPO_STRING 'c'
#define TIPO_REAL 'r'
#define TIPO_ENTERO 'e'
#define TIPO_STRUCT 's'

#define TIPO_CTE_STRING 'C'
#define TIPO_CTE_REAL 'R'
#define TIPO_CTE_ENTERO 'E'

#define TAM_TS 1000
#define TAM_TT 10000
#define TAM_PILA 1000

void error();
void eof();
void nada();
void iniid();
void contid();
void id();
void ininum();
void contnum();
void finentero();
void finreal();
void inistring();
void contstring();
void finstring();
void inibase();
void contbase();
void finbase();
void suma();
void resta();
void producto();
void division();
void mayor();
void mayorigual();
void menor();
void menorigual();
void asig();
void igual();
void distinto();
void coma();
void puntocoma();
void dospuntos();
void abrepar();
void cierrapar();
void abrecor();
void cierracor();

static int estados[CANT_ESTADOS][CANT_CARACTERES] = {
{1,2,3,4,5,0,7,8,9,10,11,13,15,17,19,20,21,22,23,24,25,28,-1,0,99,-1},
{1,1,26,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,2,3,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,3,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{4,4,4,99,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,99,4},
{-1,-1,-1,-1,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,99,-1},
{6,6,6,6,6,0,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,99,6},
{99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,99,99,99,99,99,99,99,99,99,99,99,12,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,99,99,99,99,99,99,99,99,99,99,99,14,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,99,99,99,99,99,99,99,99,99,99,99,16,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,18,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,99,-1},
{99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{27,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,99,-1},
{27,27,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,-1},
{28,28,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,29,-1,-1,-1,-1,-1,-1,-1,-1,-1,99,-1},
{-1,29,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,99,-1,99,-1}
};

static void (*funciones [CANT_ESTADOS][CANT_CARACTERES])(void) = {
{iniid,ininum,ininum,inistring,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,inibase,error,nada,eof,error},
{contid,contid,contid,id,id,id,id,id,id,id,id,id,id,id,id,id,id,id,id,id,id,id,id,id,id,error},
{finentero,contnum,contnum,finentero,finentero,finentero,finentero,finentero,finentero,finentero,finentero,finentero,finentero,finentero,finentero,finentero,finentero,finentero,finentero,finentero,finentero,finentero,finentero,finentero,finentero,error},
{finreal,contnum,finreal,finreal,finreal,finreal,finreal,finreal,finreal,finreal,finreal,finreal,finreal,finreal,finreal,finreal,finreal,finreal,finreal,finreal,finreal,finreal,finreal,finreal,finreal,error},
{contstring,contstring,contstring,finstring,contstring,contstring,contstring,contstring,contstring,contstring,contstring,contstring,contstring,contstring,contstring,contstring,contstring,contstring,contstring,contstring,contstring,contstring,contstring,contstring,finstring,contstring},
{error,error,error,error,nada,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error},
{nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada,nada},
{suma,suma,suma,suma,suma,suma,suma,suma,suma,suma,suma,suma,suma,suma,suma,suma,suma,suma,suma,suma,suma,suma,suma,suma,suma,error},
{resta,resta,resta,resta,resta,resta,resta,resta,resta,resta,resta,resta,resta,resta,resta,resta,resta,resta,resta,resta,resta,resta,resta,resta,resta,error},
{producto,producto,producto,producto,producto,producto,producto,producto,producto,producto,producto,producto,producto,producto,producto,producto,producto,producto,producto,producto,producto,producto,producto,producto,producto,error},
{division,division,division,division,division,division,division,division,division,division,division,division,division,division,division,division,division,division,division,division,division,division,division,division,division,error},
{mayor,mayor,mayor,mayor,mayor,mayor,mayor,mayor,mayor,mayor,mayor,mayor,nada,mayor,mayor,mayor,mayor,mayor,mayor,mayor,mayor,mayor,mayor,mayor,mayor,error},
{mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,mayorigual,error},
{menor,menor,menor,menor,menor,menor,menor,menor,menor,menor,menor,menor,nada,menor,menor,menor,menor,menor,menor,menor,menor,menor,menor,menor,menor,error},
{menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,menorigual,error},
{asig,asig,asig,asig,asig,asig,asig,asig,asig,asig,asig,asig,nada,asig,asig,asig,asig,asig,asig,asig,asig,asig,asig,asig,asig,error},
{igual,igual,igual,igual,igual,igual,igual,igual,igual,igual,igual,igual,igual,igual,igual,igual,igual,igual,igual,igual,igual,igual,igual,igual,igual,error},
{error,error,error,error,error,error,error,error,error,error,error,error,nada,error,error,error,error,error,error,error,error,error,error,error,error,error},
{distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,distinto,error},
{coma,coma,coma,coma,coma,coma,coma,coma,coma,coma,coma,coma,coma,coma,coma,coma,coma,coma,coma,coma,coma,coma,coma,coma,coma,error},
{abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,abrecor,error},
{cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,cierracor,error},
{abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,abrepar,error},
{cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,cierrapar,error},
{puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,puntocoma,error},
{dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,dospuntos,error},
{contid,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error},
{contid,contid,id,id,id,id,id,id,id,id,id,id,id,id,id,id,id,id,id,id,id,id,id,id,id,error},
{contbase,contbase,error,error,error,error,error,error,error,error,error,error,error,error,contbase,error,error,error,error,error,error,error,error,error,error,error},
{error,contbase,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,error,finbase,error,error,error}
};
%}

%start programa
/*comienzo palabras reservadas (deben estar en el mismo orden que en el vector)*/
%token WHILE
%token DO
%token ENDWHILE
%token IF
%token THEN
%token ELSE
%token ENDIF
%token DOCASE
%token OTHER
%token ENDCASE
%token CASE
%token STRUCT
%token OUT
%token DECLARE
%token ENDDECLARE
%token real
%token entero
%token string
%token NOT
%token AND
%token OR
/*2013*/
%token FTOC
%token FTOK
%token CTOF
%token CTOK
%token KTOC
%token KTOF
/*fin palabras reservadas*/
%token CTE_BASE
/*fin 2013*/
%token ID
%token CTE_STR
%token CTE_ENTERA
%token CTE_REAL
%token OP_SUMA
%token OP_RESTA
%token OP_MUL
%token OP_DIV
%token MAYOR
%token MAYOR_IGUAL
%token MENOR
%token MENOR_IGUAL
%token OP_ASIG
%token IGUAL
%token DISTINTO
%token COMA
%token PUNTO_COMA
%token DOS_PUNTOS
%token ABRE_PAR
%token CIERRA_PAR
%token ABRE_COR
%token CIERRA_COR
%token ABRE_LLAVE
%token CIERRA_LLAVE

%%
programa: sentencia | programa sentencia;
sentencia:	declaracion
			| asignacion {sent = asign;}
			| print {sent = escr;}
			| iteracion
			| decision
			| do_case;

declaracion: DECLARE {bloqueDeclaracion = true;} lista_declaracion ENDDECLARE {bloqueDeclaracion = false;};

lista_declaracion: linea_declaracion | lista_declaracion linea_declaracion;
linea_declaracion: declaracion_tipo | declaracion_struct;
declaracion_tipo: tipo_dato DOS_PUNTOS ABRE_COR lista_ids CIERRA_COR;

tipo_dato:	real {tipoDatoDeclaracion = TIPO_REAL;}
		| entero {tipoDatoDeclaracion = TIPO_ENTERO;}
		| string {tipoDatoDeclaracion = TIPO_STRING;};

lista_ids: ID | ID COMA lista_ids;

declaracion_struct: STRUCT {tipoDatoDeclaracion = TIPO_STRUCT; bloqueStruct = true; } 
					ID 
					ABRE_COR CTE_ENTERA CIERRA_COR 
					ABRE_PAR variables_struct CIERRA_PAR { structsize(TS[$5].valor.f);};

variables_struct: 	tipo_dato DOS_PUNTOS ID PUNTO_COMA variables_struct { verificarNombreStruct(TS[$4].nombre);}
			| tipo_dato DOS_PUNTOS ID { verificarNombreStruct(TS[$3].nombre);};

do_case: DOCASE {cant_case = 0; crearTerceto("DOCASE", "_", "_");} estructura_case resto_case;

estructura_case: CASE condicion {apilar(&sentControl, crearSaltoCondicion()+1);} programa {
			cant_case++;
			apilar(&P3, crearTerceto("CASE", "_", "_"));
			modificarTercetoDos(desapilar(&P2), 2, sent + 2);
		}
		| estructura_case CASE condicion {apilar(&sentControl, crearSaltoCondicion()+1);} programa {
			cant_case++;
			apilar(&P3, crearTerceto("CASE", "_", "_"));
			modificarTercetoDos(desapilar(&P2), 2, sent + 2);
		};

resto_case: ENDCASE {
				int i;
				sent = crearTerceto("ENDCASE", "_", "_");
				for(i = 0; i < cant_case; i++) {
					modificarTercetoTres(desapilar(&P3), 1, sent + 2);
				}
			}
			| OTHER {cant_case++;} programa ENDCASE {
				int i;
				sent = crearTerceto("ENDCASE", "_", "_");
				for(i = 0; i < cant_case; i++) {
					modificarTercetoTres(desapilar(&P3), 1, sent + 1);
				}
			};

print:	OUT ABRE_PAR CTE_STR CIERRA_PAR	{escr = crearTerceto("OUT", TS[$3].nombre, "_");}
		| OUT ABRE_PAR ID CIERRA_PAR	{escr = crearTerceto("OUT", TS[$3].nombre, "_");};

iteracion:  WHILE {apilar(&P2, cantTercetos + 1); crearTerceto("WHILE", "_", "_");}
			condicion {apilar(&sentControl, crearSaltoCondicion() + 1);}
			DO programa ENDWHILE {
				char s[8];
				if(tope(pilaCondiciones) == 1 || tope(pilaCondiciones) == 2) {
					int t1 = desapilar(&P2);
					int t2 = desapilar(&P2);
					sprintf(s, "%d", desapilar(&P2));
					sent = crearTerceto("ENDWHILE", s, "_");
					apilar(&P2,t2);
					modificarTercetoDos(t1, 2, sent + 1);		
				
				 }	else{
					int t = desapilar(&P2);
					sprintf(s, "%d", desapilar(&P2));
					sent = crearTerceto("ENDWHILE", s, "_");
					modificarTercetoDos(t, 2, sent + 1);
				}
			};

decision:	IF {crearTerceto("IF", "_", "_");}
			condicion {apilar(&sentControl,crearSaltoCondicion()+1);}
			THEN programa resto;

resto:  ENDIF {
			modificarTercetoDos(desapilar(&P2), 2, sent + 1);
			sent = crearTerceto("ENDIF", "_", "_");
		}
		| ELSE {
			sent = crearTerceto("ELSE", "_", "_");
			modificarTercetoDos(desapilar(&P2), 2, sent + 1);
			apilar(&P2, sent);
		}
		programa ENDIF {
			sent = crearTerceto("ENDIF", "_", "_");
			modificarTerceto(desapilar(&P2), 1, sent);
		};

condicion:	condicion_simple { apilar(&pilaCondiciones,0); }
			| condicion_multiple {
				switch(tipo_comp) {
				case 9:
					cond_mult = desapilar(&P1);
					switch(aux_comp) {
						case 1: sprintf(ultimaCondicion, "%s","!jb");	break; //>  : jump if not greater
						case 2: sprintf(ultimaCondicion, "%s","!jbe");  break; //>= : jump if not greater equal
						case 3: sprintf(ultimaCondicion, "%s","!jnbe");	break; //<  : jump if not below
						case 4: sprintf(ultimaCondicion, "%s","!jnb");  break; //<= : jump if not below equals
						case 5: sprintf(ultimaCondicion, "%s","!jne");	break; //!= : jump if equals
						case 6: sprintf(ultimaCondicion, "%s","!je");	break; //== : jump if not equals
					}
					break;
				}
			};
		
condicion_simple: expresion MAYOR expresion			{cond_simple = crearComparacion(1);} /* jnb */
				| expresion MAYOR_IGUAL expresion	{cond_simple = crearComparacion(2);} /* jnbe */
				| expresion MENOR expresion			{cond_simple = crearComparacion(3);} /* jbe */
				| expresion MENOR_IGUAL expresion	{cond_simple = crearComparacion(4);} /* jb */
				| expresion DISTINTO expresion		{cond_simple = crearComparacion(5);} /* je */
				| expresion IGUAL expresion			{cond_simple = crearComparacion(6);} /* jne */
				;

condicion_multiple:	condicion_simple AND {crearSaltoCondicion(); apilar(&pilaCondiciones, 1);} condicion_simple
					| condicion_simple OR {crearSaltoCondicion(); apilar(&pilaCondiciones, 2);} condicion_simple
					| NOT condicion_simple {aux_comp = tipo_comp; tipo_comp = 9;};

asignacion: ID OP_ASIG expresion {asign = crearAsignacion(TS[$1].nombre);};

expresion: expresion OP_SUMA termino  {expr = crearOperacion("+");}
	     | expresion OP_RESTA termino {expr = crearOperacion("-");}
	     | termino {expr = term;};

termino:  termino OP_MUL factor {term = crearOperacion("*");}
	    | termino OP_DIV factor {term = crearOperacion("/");}
	    | factor {term = fact;};

factor:   ID            {apilar(&P1, fact = crearTerceto(TS[$1].nombre, "_", "_"));}
	    | CTE_ENTERA	{apilar(&P1, fact = crearTerceto(TS[$1].nombre, "_", "_"));}
	    | CTE_REAL  	{apilar(&P1, fact = crearTerceto(TS[$1].nombre, "_", "_"));}
	    | CTE_STR	    {apilar(&P1, fact = crearTerceto(TS[$1].nombre, "_", "_"));}
	    | ABRE_PAR expresion CIERRA_PAR
	    | temperatura
	    | base;

base: ABRE_LLAVE CTE_BASE CIERRA_LLAVE;

temperatura:  FTOC ABRE_PAR numero CIERRA_PAR {temperatura("ftoc", TS[$3].valor.f);}
            | FTOK ABRE_PAR numero CIERRA_PAR {temperatura("ftok", TS[$3].valor.f);}
            | CTOF ABRE_PAR numero CIERRA_PAR {temperatura("ctof", TS[$3].valor.f);}
            | CTOK ABRE_PAR numero CIERRA_PAR {temperatura("ctok", TS[$3].valor.f);}
            | KTOC ABRE_PAR numero CIERRA_PAR {temperatura("ktoc", TS[$3].valor.f);}
            | KTOF ABRE_PAR numero CIERRA_PAR {temperatura("ktof", TS[$3].valor.f);};

numero: CTE_ENTERA | CTE_REAL;
%%

/*Estructuras para la Tabla de Simbolos y la Pila*/

union sValor {
	double f; //para enteros y flotantes
	char *s; //para constantes string
};

typedef struct{
	char *nombre;
	char tipo;
	union sValor valor;
	int longitud;
} t_tablaSimbolos;

typedef struct {
	int base[TAM_PILA];
	int tope;
} pila;

/*Fin estructuras*/

/*variables globales generales*/
t_tablaSimbolos TS[TAM_TS];
int cantElementosTS, posicionTS;
//P1: factores, P2: saltos, P3: docase;
pila P1, P2, P3;
//se usan pilas por si hay condiciones multiples anidadas
pila sentControl;//se usa para saltar si la 1º condicion del or es true
pila pilaCondiciones;//1:and 2:or

FILE *archivoEntrada;
int linea = 1;
int tipoToken, longitud, cantCteString = 0;
char caracter, *pcToken, cToken[MAX*2], tipoDatoDeclaracion, structname[MAX];
double valorCteEntera, valorCteReal;

typedef enum { false, true } bool;
bool bloqueDeclaracion = false;
bool bloqueStruct = false;
bool vinoAnd;
bool vinoOr;

//tercetos
int expr, term, fact , asign, sent, escr, cond_simple, cond_mult, tipo_comp, aux_comp, cant_comp, cant_case;
char temp[MAX*2];
FILE *intermedio;
char ultimaCondicion[8];
struct tercetos t;

/*vector de palabras reservadas (deben estar en el mismo orden que los tokens)*/
char palabrasReservadas[CANT_RESERV][MAX/2] = {
"while","do","endwhile","if","then","else","endif","docase","other","endcase","case","struct","out","declare","enddeclare","real","entero","string","not","and","or",
"ftoc","ftok","ctof","ctok","ktoc","kotf"
};

//assembler
FILE *assembler;

typedef struct etiquetas {
	int numero_t;
	char nombre[30];  
} etiquetas;
  
etiquetas etiqueta[100];
int cant_etq = 0;
int cont_cond = 0;
pila PI;

//devuelve el nombre del tipo a partir del char sin importar si es constante o no.
char* nombreTipo(char tipo) {
	switch(tipo) {
		case 'c': case 'C': return "string";
		case 'r': case 'R': return "real";
		case 'e': case 'E': return "entero";
		case 's': return "struct";
		default: return "";
	}
}

//devuelve el numero de columna de la matriz a partir del caracter pasado por parametro
int getcolumna(char c) {
	if(isalpha(c)) {
		return 0;
	}
	if(isdigit(c)) {
		return 1;
	}
	switch(c) {
		case '.': return 2;
		case '"': return 3;
		case '#': return 4;
		case '\n':
		case '\r':
			return 5;
		case '+': return 6;
		case '-': return 7;
		case '*': return 8;
		case '/': return 9;
		case '>': return 10;
		case '<': return 11;
		case '=': return 12;
		case '!': return 13;
		case ',': return 14;
		case '[': return 15;
		case ']': return 16;
		case '(': return 17;
		case ')': return 18;
		case ';': return 19;
		case ':': return 20;
		case '{': return 21;
		case '}': return 22;
		case ' ':
		case '\t':
			return 23;
		case EOF:
			return 24;
		default:
			return 25;
	}
}

/*Manejo de la Pila*/
void crearPila(pila *p) { p->tope = -1; }
bool esVacia(pila p) { return (p.tope < 0); }
bool esLlena(pila p) { return (p.tope + 1 == TAM_PILA); }

bool apilar(pila *p, int d) {
	if(esLlena(*p)) return false;
	p->base[++p->tope] = d; return true;
}

int desapilar(pila *p) {
	if(esVacia(*p)) return -1;
	return p->base[p->tope--];
}

int tope(pila p) {
	if(esVacia(p)) return -1;
	return p.base[p.tope];   
}
  
void imprimePila(pila *p) {
	pila *aux = p;
	while( !esVacia(*aux) ) { 
		printf("%d --> ", aux->base[aux->tope--]);
	}
}
 
/*Funciones de la tabla de simbolos*/

//recorre la tabla de simbolos y muestra sus valores.
void mostrarTablaSimbolos() {
	int i;
	printf("/-----Tabla de simbolos-----/\n");
	printf("Pos \t\t\t Nombre \t\t\t   Tipo   \t   Long   Valor\n");
	for(i = 0; i < cantElementosTS; i++) {
		printf("%2d | %-31s | %-10s | %2d | ", i, TS[i].nombre, nombreTipo(TS[i].tipo), TS[i].longitud);
		if(TS[i].tipo == TIPO_STRING || TS[i].tipo == TIPO_CTE_STRING) {
		   printf("%s", TS[i].valor.s);
		}else{
		   printf("%f", TS[i].valor.f);	
		}
		printf("\n");
	}
}

//devuelve la posicion del id en la TS o -1 si no lo encuentra
int buscarIDenTS(char *simbolo) {
	int i;
	for(i = 0; i < cantElementosTS; i++) {
		if(strncmp(TS[i].nombre, simbolo, MAX) == 0) {
			return i;
		}
	}
	return -1;
}

//devuelve la posicion del simbolo en la TS o -1 si no lo encuentra
int buscarSimboloenTS(const char *simbolo) {
	int i;
	for(i = 0; i < cantElementosTS; i++) {
		if(strncmp(TS[i].nombre, simbolo, MAX) == 0 || TS[i].nombre[0] == '_' && strncmp(TS[i].nombre + 1, simbolo, MAX) == 0) {
			return i;
		}
	}
   return -1;
}

//devuelve la posicion del simbolo con ese tipo en la TS o -1 si no lo encuentra
int buscarEnTablaSimbolos(char *simbolo, char tipo) {
	int i;
	bool esid = tipo >= 'a';
	int inc = esid ? 0 : 1;
	for(i = 0; i < cantElementosTS; i++) {
		if(strncmp(TS[i].nombre + inc, simbolo, MAX) == 0 && TS[i].tipo == tipo) {
			return i;
		}
	}
	return -1;
}

//devuelve la posicion del string en la TS o -1 si no lo encuentra
int buscarStringEnTS(char *valor) {
	int i;
	for(i = 0; i < cantElementosTS; i++) {
		if(TS[i].tipo == TIPO_CTE_STRING && TS[i].valor.s != NULL && strncmp(TS[i].valor.s, valor, MAX) == 0) {
			return i;
		}
	}
	return -1;
}

//agrega en la tabla de simbolos el nombre, tipo, valor y longitud pasado por parametro y retorna la posicion en la misma.
int agregarTablaSim(char *nombre, char tipo, union sValor valor, int longitud) {
	char cpVariable[MAX*2] = "";
	if(tipoToken != ID) cpVariable[0] = '_';

	TS[cantElementosTS].nombre = (char*)malloc(sizeof(char)*(MAX*2));
	strcat(cpVariable, nombre);
	strcpy(TS[cantElementosTS].nombre, cpVariable);

	TS[cantElementosTS].tipo = tipo;

	TS[cantElementosTS].longitud = longitud;

	if(tipo == TIPO_STRING || tipo == TIPO_CTE_STRING) {
		TS[cantElementosTS].valor.s = (char*)malloc(sizeof(char)*(strlen(valor.s) + 1));
		strcpy(TS[cantElementosTS].valor.s, valor.s);
	}else{
		TS[cantElementosTS].valor.f = valor.f;
	}
	return cantElementosTS++;
}

//Valida que el campo del struct coincida con el nombre de la estructura y contenga un punto
void verificarNombreStruct(char *campoStruct) {	
	//verifico si tiene el punto
	char *p = strchr(campoStruct, '_');
	if(p == NULL || strncmp(campoStruct, structname, p - campoStruct) != 0) {
		p = strchr(campoStruct, '_');
		if(p != NULL) *p = '.';
		printf("Linea: %d. Error: el campo '%s' de la estructura '%s' no respeta el formato de declaracion.\n", linea, campoStruct, structname);
		exit(0);
	}
}

//guarda el tamanio del struct en la TS
void structsize(double tam) {
	int cant = 0, pos, i;
	for(i = 0; i < cantElementosTS; i++) {
		if(strncmp(TS[i].nombre, structname, strlen(structname)) == 0) {
			if(strncmp(TS[i].nombre, structname, MAX) == 0) {
				pos = i;
			} else if(strchr(TS[i].nombre, '_')){
				cant++;
			}
		}
	}
	if(cant != tam) {
		printf("Linea: %d. Error: la cantidad de campos del struct '%s'(%d) no coincide con el tamanio declarado(%0.0f).\n", linea, TS[pos].nombre, cant, tam);
		exit(0);
	}
	TS[pos].longitud = cant;
}

/*Manejo de la tabla de tercetos*/

typedef struct tercetos {
	int posicion;
	char operador[MAX*2];
	char arg1[MAX*2];
	char arg2[MAX*2];
} tercetos;

tercetos tt[TAM_TT];
int cantTercetos = 0;

/* funciones de tercetos */

bool validable(char c) {
	switch(c) {
	case '+':
	case '-':
	case '*':
	case '/':
	case '=':
	case '?':
		return true;
	default:
		return false;
	}
}

char toLowercase(char t) {
	return t >= 'a' ? t : t + ('a' - 'A');
}

//obtiene el simbolo basico (sin corchetes) recorriendo la tt y lo guarda en temp.
void obtenerSimboloTT(const char *arg) {
	if(arg[0] == '[') {
		strcpy(temp, arg+1);
		temp[strlen(arg)-2] = '\0';
	} else {
		strcpy(temp, arg);
	}
	while(isdigit(temp[0])) {
		int pos = atoi(temp) - 1;
		strcpy(temp, tt[pos].operador);
		if(buscarSimboloenTS(temp) == -1) {
			strcpy(temp, tt[pos].arg1);
		}
	}
}

//devuelve el char del tipo sin importar si es constante o no, si el id no está en la TS devuelve el char blanco.
char obtenerTipo(const char *arg) {
	obtenerSimboloTT(arg);
	int pos = buscarSimboloenTS(temp);

	if(pos != -1) {
		return toLowercase(TS[pos].tipo);
	}
	return ' ';
}

int crearTerceto(char *op, char *arg1, char *arg2) {
	//comprobacion de tipos
	if(validable(op[0])) {
		char tipo1 = obtenerTipo(arg1);
		char tipo2 = obtenerTipo(arg2);
		if(tipo1 != tipo2) {
			obtenerSimboloTT(arg1); strcpy(arg1, temp); if(arg1[0] == '_') arg1++;
			obtenerSimboloTT(arg2); strcpy(arg2, temp); if(arg2[0] == '_') arg2++;
			printf("Linea %d. Tipos incompatibles: '%s'(%s) y '%s'(%s)\n", linea, arg1, nombreTipo(tipo1), arg2, nombreTipo(tipo2));
			exit(0);
		}
		
		if(tipo1 == TIPO_STRUCT) {
		    printf("Linea %d. No es posible comparar estructuras.\n", linea);
		    exit(0);
		}
	}	
	
	if(cantTercetos == TAM_TT) return -1;
	tt[cantTercetos].posicion = cantTercetos + 1;
	strcpy(tt[cantTercetos].operador, op);
	strcpy(tt[cantTercetos].arg1, arg1);
	strcpy(tt[cantTercetos].arg2, arg2);
	return ++cantTercetos;
}

void mostrarTT() {
	int i;
	printf("/-----Tercetos-----/\n");
	printf("Terceto Operador Arg1 Arg2\n");
	for(i = 0; i != cantTercetos; i++) {
		printf("%2d (%s, %s, %s)\n", tt[i].posicion, tt[i].operador, tt[i].arg1, tt[i].arg2);
	}
}

void leerTerceto(FILE *fd, struct tercetos *t) {
	char s[MAX*2];
	fscanf(fd, "%s", s);
	t->posicion = atoi(&s[0]);
	fscanf(fd, "%s", s);

	fscanf(fd, "%s", s);
	strcpy(t->operador, s);
	fscanf(fd, "%s", s);

	fscanf(fd, "%s", s);
	strcpy(t->arg1, s);
	fscanf(fd, "%s", s);

	fscanf(fd, "%s", s);
	strcpy(t->arg2, s);
	fscanf(fd, "%s", s);
}

void inicializarTercetos(){
	crearTerceto("EOP", "_", "_");
}

void grabarTercetos() {
	if((intermedio = fopen("intermedia.txt", "w")) == NULL) {
		printf("Error de creacion del archivo intermedia.txt _");
		exit(0);
	}

	int pos;
	char arg1[MAX*2], arg2[MAX*2];
	inicializarTercetos();
	for(pos = 0; pos != cantTercetos; pos++) {
		if(isdigit(tt[pos].arg1[0])) sprintf(arg1, "[ %s ]", tt[pos].arg1);
		else sprintf(arg1, " %s ", tt[pos].arg1);
		if(isdigit(tt[pos].arg2[0])) sprintf(arg2, "[ %s ]", tt[pos].arg2);
		else sprintf(arg2, " %s ", tt[pos].arg2);
		fprintf(intermedio, "%d ( %s ,%s,%s)\n", tt[pos].posicion, tt[pos].operador, arg1, arg2);
	}
	fclose(intermedio);
}

// t: numero de terceto (1-based)
// a: numero de argumento (0:op, 1:arg1, 2:arg2)
void modificarTerceto(int t, int a, int val) {
	sprintf(temp, "%d", val);
	switch(a) {
		case 0: strcpy(tt[t-1].operador, temp); break;
		case 1: strcpy(tt[t-1].arg1, temp); break;
		case 2: strcpy(tt[t-1].arg2, temp); break;
	}
}

void temperatura(char* conv, double val) {
    const double K = 273.14;
	if(strcmp(conv, "ctof") == 0) {
		valorCteReal = 1.8*val + 32;
	} else if(strcmp(conv, "ftoc") == 0) {
		valorCteReal = (val - 32) / 1.8;
	} else if(strcmp(conv, "ctok") == 0) {
		valorCteReal = val + K;
	} else if(strcmp(conv, "ktoc") == 0) {
		valorCteReal = val - K;
	} else if(strcmp(conv, "ftok") == 0) {
		valorCteReal = (val - 32) / 1.8 + K;
	} else if(strcmp(conv, "ktof") == 0) {
		valorCteReal = 1.8*(val - K) + 32;
	}

	char nombre[MAX*2];
    sprintf(nombre, "%f", valorCteReal);
    *strchr(nombre, '.') = '_';
    //quitar ceros a la derecha
	char *p = strchr(nombre, '\0');
    while(--p != nombre && *p == '0') ;
    *(p+1) = '\0';

	if((yylval = buscarEnTablaSimbolos(nombre, TIPO_CTE_REAL)) == -1) {
		union sValor valor;
		valor.f = valorCteReal;
		yylval = agregarTablaSim(nombre, TIPO_CTE_REAL, valor, 0);
	}

	posicionTS = yylval;
	tipoToken = CTE_REAL;

    apilar(&P1, fact = crearTerceto(TS[posicionTS].nombre, "_", "_"));
}

char* MatrizSaltos[6][2] = {
	"!jnb", "!jb",
	"!jnbe", "!jbe",
	"!jbe", "!jnbe",
	"!jb", "!jnb",
	"!je", "!jne",
	"!jne", "!je"	
};

char *obtenerSaltoNegado(char *op){
	int i;
	for(i=0;i<6;i++){
		if(!strcmp(MatrizSaltos[i][0],op)) {
			return MatrizSaltos[i][1]; 
		}
	}
}

// t: numero de terceto (1-based)
// a: numero de argumento (0:op, 1:arg1, 2:arg2)
void modificarTercetoDos(int t, int a, int val) {
	sprintf(temp, "%d", val);

	int valor = desapilar(&pilaCondiciones);

	if(valor == 1){
		modificarTerceto(t, a, val);
		int otroTerceto = desapilar(&P2);
		modificarTerceto(otroTerceto, a, val);	
	 }else if(valor == 2){
		
		switch(a) {
			case 0: strcpy(tt[t-1].operador, temp); break;
			case 1: strcpy(tt[t-1].arg1, temp); break;
			case 2: strcpy(tt[t-1].arg2, temp); break;
		}
		
		char operador[MAX*2];
		int numeroTerceto = desapilar(&P2);
		strcpy(operador, obtenerSaltoNegado(tt[numeroTerceto-1].operador));
		strcpy(tt[numeroTerceto-1].operador, operador); 
		
		char numeroTemp[MAX*2];
		sprintf(numeroTemp, "%d", tope(sentControl));
		strcpy(tt[numeroTerceto-1].arg2, numeroTemp);	
	 }else{
	 	switch(a) {
			case 0: strcpy(tt[t-1].operador, temp); break;
			case 1: strcpy(tt[t-1].arg1, temp); break;
			case 2: strcpy(tt[t-1].arg2, temp); break;
		}	 
	  }
	  desapilar(&sentControl);
}  

// t: numero de terceto (1-based)
// a: numero de argumento (0:op, 1:arg1, 2:arg2)
void modificarTercetoTres(int t, int a, int val) {
	sprintf(temp, "%d", val);

	int valor = desapilar(&pilaCondiciones);

	if(valor == 1){
		modificarTerceto(t, a, val);
		int otroTerceto = desapilar(&P3);
		modificarTerceto(otroTerceto, a, val);	
	 }else if(valor == 2){
		switch(a) {
			case 0: strcpy(tt[t-1].operador, temp); break;
			case 1: strcpy(tt[t-1].arg1, temp); break;
			case 2: strcpy(tt[t-1].arg2, temp); break;
		}
		
		char operador[MAX*2];
		int numeroTerceto = desapilar(&P3);
		strcpy(operador, obtenerSaltoNegado(tt[numeroTerceto-1].operador));
		strcpy(tt[numeroTerceto-1].operador, operador); 
		
		char numeroTemp[MAX*2];
		sprintf(numeroTemp, "%d", tope(sentControl));
				
		strcpy(tt[numeroTerceto-1].arg2, numeroTemp);	
		
	 }else{

	 	switch(a) {
		case 0: strcpy(tt[t-1].operador, temp); break;
		case 1: strcpy(tt[t-1].arg1, temp); break;
		case 2: strcpy(tt[t-1].arg2, temp); break;
		}	 
	  }
	  desapilar(&sentControl);
}  

int crearAsignacion(char *nombre) {
	int a, i, j;
	char s[8];
	sprintf(s, "%d", desapilar(&P1));
	if(obtenerTipo(nombre) != TIPO_STRUCT) {
		apilar(&P1, a = crearTerceto("=", nombre, s));
	} else {
		cantTercetos--;
		char *nombreizq = nombre;
		int izq = buscarEnTablaSimbolos(nombreizq, TIPO_STRUCT);
		obtenerSimboloTT(s);
		char *nombreder = temp;
		int der = buscarEnTablaSimbolos(nombreder, TIPO_STRUCT);
		if(izq == -1 || der == -1) {
			printf("Linea %d. Tipos incompatibles: '%s'(%s) y '%s'(%s)\n", linea, nombreizq, nombreTipo(obtenerTipo(nombreizq)), nombreder, nombreTipo(obtenerTipo(nombreder)));
			exit(1);
		}
		if(TS[izq].longitud != TS[der].longitud) {
			printf("Linea %d. Tamanios incompatibles: '%s'(%d) y '%s'(%d)\n", linea, nombreizq, TS[izq].longitud, nombreder, TS[der].longitud);
			exit(1);
		}
		
		i = izq + 1;
		j = der + 1;
		if(strncmp(TS[i].nombre, nombreizq, strlen(nombreizq)) != 0)	i++;		
		if(strncmp(TS[j].nombre, nombreder, strlen(nombreder)) != 0)	j++;
		int n;
		for(n = 0; n < TS[izq].longitud; n++) {
			apilar(&P1, a = crearTerceto("=", TS[i++].nombre, TS[j++].nombre));
		}		
	}
	
	return a;
}	  

int crearOperacion(char *op) {
	int x, y;
	char s1[8], s2[8];
	sprintf(s2, "%d", y = desapilar(&P1));
	sprintf(s1, "%d", x = desapilar(&P1));
	apilar(&P1, crearTerceto(op, s1, s2));
	return x;
}

int crearComparacion(int tipo) {
	int ret;
	char s1[8], s2[8];
	sprintf(s2, "%d", desapilar(&P1));
	sprintf(s1, "%d", desapilar(&P1));

	if(cant_comp == 0) {
		ret = crearTerceto("?CMP1", s1, s2);
		cant_comp = 1;
	} else {
		ret = crearTerceto("?CMP2", s1, s2);
	}
	if(obtenerTipo(s1) == TIPO_CTE_STRING || obtenerTipo(s1) == TIPO_STRING || obtenerTipo(s2) == TIPO_CTE_STRING || obtenerTipo(s2) == TIPO_STRING) {
		printf("Linea %d. No es posible comparar strings.\n", linea);
		exit(0);
	}
	
	apilar(&P1, ret);
	tipo_comp = tipo;
	return ret;
}

int crearSaltoCondicion() {
	int t;
	char s[8];
	switch(tipo_comp) {
		case 1: sprintf(s, "%d", cond_simple); t = crearTerceto("!jnb" , s, "_"); break; //>  : jump if not greater
		case 2: sprintf(s, "%d", cond_simple); t = crearTerceto("!jnbe", s, "_"); break; //>= : jump if not greater equal
		case 3: sprintf(s, "%d", cond_simple); t = crearTerceto("!jbe" , s, "_"); break; //<  : jump if not below
		case 4: sprintf(s, "%d", cond_simple); t = crearTerceto("!jb"  , s, "_"); break; //<= : jump if not below equals
		case 5: sprintf(s, "%d", cond_simple); t = crearTerceto("!je"  , s, "_"); break; //!= : jump if equals
		case 6: sprintf(s, "%d", cond_simple); t = crearTerceto("!jne" , s, "_"); break; //== : jump if not equals
		case 9: sprintf(s, "%d", cond_mult); t = crearTerceto(ultimaCondicion , s, "_"); break; //NOT: jump if not equals
	}
	cant_comp = 0;
	apilar(&P2, t);
	return t;
}

/*devuelve 0 cuando encuentra el EOF*/
int yylex() {
	int estado = 0;
	int columna;

	while(estado != 99) {
		caracter = fgetc(archivoEntrada);

		columna = getcolumna(caracter);

		(*funciones[estado][columna])();

		estado = estados[estado][columna];

		if(columna == 5 && estado == 0){
			linea++;
		}
	}

	if(caracter != EOF)
		fseek(archivoEntrada, -1, SEEK_CUR);

	return tipoToken;
}


/* Rutinas generales de ASM*/
void rutinasasm() {
fprintf(assembler, "\
; RUTINAS GENERALES\n\
; devuelve en BX la cantidad de caracteres que tiene un string\n\
; DS:SI apunta al string.\n\
STRLEN PROC\n\
\tmov bx,0\n\
STRL01:\n\
\tcmp byte ptr[SI+BX],24h\n\
\tje STREND\n\
\tinc BX\n\
\tjmp STRL01\n\
STREND:\n\
\tret\n\
STRLEN ENDP\n");

fprintf(assembler, "\
; copia DS:SI a ES:DI; busca la cantidad de caracteres\n\
COPIAR PROC\n\
\tcall STRLEN ; busco la cantidad de caracteres\n\
\tcmp bx,MAXTEXTSIZE\n\
\tjle COPIARSIZEOK\n\
\tmov bx,MAXTEXTSIZE\n\
COPIARSIZEOK:\n\
\tmov cx,bx ; la copia se hace de ’CX’ caracteres\n\
\tcld ; cld es para que la copia se realice hacia adelante\n\
\trep movsb ; copia la cadena\n\n\
\tmov al,24h ; carácter terminador\n\
\tmov BYTE PTR [DI],al ; el registro DI quedo apuntando al final\n\
\tret\n\
COPIAR ENDP\n\n");

fprintf(assembler, "\
; concatena DS:SI al final de ES:DI.\n\
; busco el size del primer string\n\
; sumo el size del segundo string\n\
; si la suma excede MAXTEXTSIZE, copio solamente MAXTEXTSIZE caracteres\n\
; si la suma NO excede MAXTEXTSIZE, copio el total de caracteres que tiene el segundo string\n\
\tCONCAT PROC\n\
\tpush ds\n\
\tpush si\n\
\tcall STRLEN ; busco la cantidad de caracteres del 2do string\n\
\tmov dx,bx ; guardo en DX la cantidad de caracteres en el origen.\n\
\tmov si,di\n\
\tpush es\n\
\tpop ds\n\
\tcall STRLEN ; tama#o del 1er string\n\
\tadd di,bx ; DI ya queda apuntando al final del primer string\n\
\tadd bx,dx ; tama#o total\n\
\tcmp bx,MAXTEXTSIZE ; excede el tama#o maximo?\n\
\tjg CONCATSIZEMAL\n\
CONCATSIZEOK: ; La suma no excede el maximo, copio todos\n\
\tmov cx,dx ; los caracteres del segundo string.\n\
\tjmp CONCATSIGO\n\
CONCATSIZEMAL: ; La suma de caracteres de los 2 strings exceden el maximo\n\
\tsub bx,MAXTEXTSIZE\n\
\tsub dx,bx\n\
\tmov cx,dx ; copio lo maximo permitido el resto se pierde.\n\
CONCATSIGO:\n\
\tpush ds\n\
\tpop es\n\
\tpop si\n\
\tpop ds\n\
\tcld ; cld es para que la copia se realice hacia adelante\n\
\trep movsb ; copia la cadena\n\
\tmov al,24h ; carácter terminador\n\
\tmov BYTE PTR [DI],al ; el registro DI quedo apuntando al final\n\
\tret\n\
CONCAT ENDP\n\n");

fprintf(assembler, "\
NEWLINE PROC\n\
\tpush dx\n\
\tpush eax\n\
\tmov DX, OFFSET _newline\n\
\tmov ah,09\n\
\tint 21h\n\
\tpop eax\n\
\tpop dx\n\
\tret\n\
NEWLINE ENDP\n\n");

fprintf(assembler, "\
IMPRIMIR_DEC PROC\n\
\tpush eax\n\
\tpush ebx\n\
\tpush ecx\n\
\tpush edx\n\
\txor ecx,ecx\n\
\tmov ebx,10d\n\
imp_dec_loop1:\n\
\txor edx,edx\n\
\tdiv ebx\n\
\tpush edx\n\
\tinc ecx\n\
\tcmp eax,0\n\
\tjnz imp_dec_loop1\n\
\tmov ah,02\n\
imp_dec_loop2:\n\
\tpop edx\n\
\tadd dl,48D\n\
\tint 21h\n\
\tdec ecx\n\
\tjnz imp_dec_loop2\n\
\tpop edx\n\
\tpop ecx\n\
\tpop ebx\n\
\tpop eax\n\
\tcall NEWLINE\n\
\tret\n\
IMPRIMIR_DEC ENDP\n\n");

fprintf(assembler, "\
PUTC	MACRO   char\n\
	PUSH	AX\n\
	MOV	 AL, char\n\
	MOV	 AH, 0Eh\n\
	INT	 10h\n\
	POP	 AX\n\
ENDM\n\
PRINT_NUM_UNS   PROC\n\
	PUSH	AX\n\
	PUSH	BX\n\
	PUSH	CX\n\
	PUSH	DX\n\
	MOV	 CX, 1\n\
	MOV	 BX, 10000  \n\
	CMP	 AX, 0\n\
	JZ	  print_zero1\n\
begin_print:\n\
	CMP	 BX,0\n\
	JZ	  end_print1\n\
	CMP	 CX, 0\n\
	JE	  calc\n\
	CMP	 AX, BX\n\
	JB	  skip1\n\
calc:\n\
	MOV	 CX, 0  \n\
	MOV	 DX, 0\n\
	DIV	 BX \n\
	ADD	 AL, 30h	\n\
	PUTC	AL\n\
	MOV	 AX, DX  \n\
skip1:\n\
	PUSH	AX\n\
	MOV	 DX, 0\n\
	MOV	 AX, BX\n\
	DIV	 CS:ten \n\
	MOV	 BX, AX\n\
	POP	 AX\n\
	JMP	 begin_print\n\
print_zero1:\n\
	PUTC	'0'\n\
end_print1:\n\
	POP	 DX\n\
	POP	 CX\n\
	POP	 BX\n\
	POP	 AX\n\
	RET\n\
PRINT_NUM_UNS   ENDP\n\
IMPRIMIR_REAL PROC\n\
	PUSHAD\n\
	FSTCW OldCW\n\
	FWAIT\n\
	MOV   AX,OldCW\n\
	AND   AX,0F3FFh\n\
	OR	AX,0C00h\n\
	MOV   NewCW, AX\n\
	FLDCW NewCW\n\
	MOV   EAX, DWORD PTR [SI]\n\
	MOV   AUX_1, EAX\n\
	TEST  EAX, 80000000h\n\
	JE	POSITIVE\n\
	PUTC  '-'\n\
	AND   EAX, 7FFFFFFFh\n\
	MOV   AUX_1, EAX\n\
POSITIVE:\n\
	FLD   AUX_1\n\
	FIST  AUX_1\n\
	MOV   EAX, AUX_1\n\
	CALL  PRINT_NUM_UNS\n\
	PUTC  '.'\n\
	FILD  AUX_1\n\
	FSUBP\n\
	MOV   AUX_1, 64h\n\
	FILD  AUX_1\n\
	FMULP\n\
	FISTP AUX_1\n\
	MOV   EAX, AUX_1\n\
	CALL  PRINT_NUM_UNS\n\
	PUTC  0Dh\n\
	PUTC  0Ah\n\
	FLDCW OldCW\n\
	POPAD\n\
	RET\n\
IMPRIMIR_REAL ENDP\n\n");
}

void datosasm() {
	fprintf(assembler, "MAXTEXTSIZE equ 50\n");
	fprintf(assembler,"TRUE equ 1\n"); 
	fprintf(assembler,"FALSE equ 0\n");

	//variables auxiliares para hacer cálculos generales, out, mensaje de espera , etc.
	fprintf(assembler,"\n; Variables auxiliares y mensajes de validacion");
	fprintf(assembler,"\n__string_aux1 db 30 dup (?),'$'");
	fprintf(assembler,"\n__string_aux2 db 30 dup (?),'$'\n");

	//variables para almacenar resultados de las comparaciones
	fprintf(assembler,"__bool_aux1 dw ?\n");
	fprintf(assembler,"__bool_aux2 dw ?\n");
	fprintf(assembler,"__float_aux1 dd ?\n");
	
	//variables necesarias para el OUT de los reales.
	fprintf(assembler,"ten DW 10\n");
	fprintf(assembler,"AUX_1 DD ?\n");
	fprintf(assembler,"OldCW DW ?\n");
	fprintf(assembler,"NewCW DW ?\n");
	
	fprintf(assembler,"msgPRESIONE db 0DH,0AH,\"Presione una tecla para continuar...\",'$'\n");
	fprintf(assembler,"_NEWLINE db 0Dh,0Ah,'$'\n");
	fprintf(assembler,"msgERROR_LIMITE db 0DH,0AH,\"Error en los limites...\",'$'\n");
	
	int i,j;
	for(i = 0; i < cantElementosTS; i++) {
		if(TS[i].tipo == TIPO_CTE_STRING) {
			fprintf(assembler, "%s db \"%s\",'$',%d dup (?)\n", TS[i].nombre, TS[i].valor.s, TS[i].longitud);
		}
		if(TS[i].tipo == TIPO_STRING) {
			fprintf(assembler, "%s db MAXTEXTSIZE dup (?),'$'\n", TS[i].nombre);
		}

		if(TS[i].tipo == TIPO_REAL) {
			fprintf(assembler, "%s dd ?\n", TS[i].nombre);
		}

		if(TS[i].tipo == TIPO_CTE_REAL) {
			fprintf(assembler, "%s dd %f\n", TS[i].nombre, TS[i].valor.f);
		}

		if(TS[i].tipo == TIPO_ENTERO) {
			fprintf(assembler, "%s dd ?\n", TS[i].nombre);
		}
		
		if(TS[i].tipo == TIPO_CTE_ENTERO) {
			fprintf(assembler, "%s dd %f\n", TS[i].nombre, TS[i].valor.f);
		}
	}
}

/* Función para crear el salto y la etiqueta correpondiente. El salto lo pone directo en el archivo, la etiqueta la pone después cuando llega al número de terceto destino. */
void crearSaltoEtiqueta(char *tipo_salto) {
	char aux1[10], aux2[10];
	strcpy(aux2, "SALTO");
	sprintf(aux1, "%d", ++cont_cond);
	strcat(aux2, aux1);
	fprintf(assembler, "%s %s\n", tipo_salto, aux2);  
	etiqueta[cant_etq].numero_t = atoi(t.arg2);
	strcpy(etiqueta[cant_etq].nombre, aux2);
	cant_etq++;
}

void limpiarStack() {
fprintf(assembler, "\
ffree st(0)\n\
ffree st(1)\n\
ffree st(2)\n\
ffree st(3)\n\
ffree st(4)\n\
ffree st(5)\n\
ffree st(6)\n\
ffree st(7)\n\
");
}

void codigoasm() {
	//cargo todas las rutinas necesarias
	rutinasasm();
	
	//empieza el main
	fprintf(assembler, "\nMAIN:\n");
	fprintf(assembler, "mov AX, @DATA\n");
	fprintf(assembler, "mov DS, AX\nmov ES, AX\n");
	fprintf(assembler, "\nFINIT");
	fprintf(assembler, "\nFFREE; inicializacion del co-procesador\n");
	
	int i;
	int cant_string = 0;
	int cont_if = 0, cont_while = 0, cont_case = 0;
	int pos; //posicion en la ts
	char aux1[MAX], aux2[MAX];
	crearPila(&PI);
	bool concatString = false; //validar concatenacion de maximo 2 string
	
	//los tercetos los leo de intermedia.txt
	if((intermedio = fopen("intermedia.txt", "rb+")) == NULL) {
		printf("Error de creacion del archivo intermedia.txt _");
		exit(0);
	}
		
	while(!feof(intermedio)){
	
		leerTerceto(intermedio,&t);

		//me fijo si tengo que grabar alguna etiqueta creada anteriormente.
		int it;
		for(it = 0; it < cant_etq; it++)
			if(etiqueta[it].numero_t == t.posicion)
				fprintf(assembler,"%s:\n", etiqueta[it].nombre);
		
		switch(t.operador[0]) {
		case '+':
			if(obtenerTipo(t.arg2) == TIPO_STRING) {
				if(concatString) {
					printf("Linea: %d. Error: no es posible concatenar mas de dos string.\n", linea);
					exit(1);
				}
				concatString = true;
				obtenerSimboloTT(t.arg2);
				char *nombreString = temp;
				fprintf(assembler, "mov si, OFFSET %s\n", nombreString);
				fprintf(assembler, "mov di, OFFSET __string_aux1\n");
				fprintf(assembler, "call CONCAT\n");
			} else {
				fprintf(assembler, "fadd\n");
			}
			break;
		case '-': fprintf(assembler, "fsub\n"); break;
		case '*': fprintf(assembler, "fmul\n"); break;
		case '/': fprintf(assembler, "fdiv\n"); break;
		}

		//verifico si en el operador viene una variable/constante
		pos = buscarIDenTS(t.operador);
		if( pos != -1) {
			if(TS[pos].tipo == TIPO_CTE_ENTERO) {
				fprintf(assembler, "fld %s\n", t.operador);
			}
			if(TS[pos].tipo == TIPO_ENTERO) {
				fprintf(assembler, "fild %s\n", t.operador);
			}

			if(TS[pos].tipo == TIPO_CTE_REAL || TS[pos].tipo == TIPO_REAL) 
				fprintf(assembler, "fld %s\n", t.operador);  
			
			if(TS[pos].tipo == TIPO_CTE_STRING || TS[pos].tipo == TIPO_STRING) {
				fprintf(assembler, "mov si, OFFSET %s\n", t.operador);
				if(cant_string == 0) {
					fprintf(assembler, "mov di, OFFSET __string_aux1\n");
					cant_string = 1;
				} else {
					fprintf(assembler, "mov di, OFFSET __string_aux2\n");
					cant_string = 0;  
				}
				fprintf(assembler,"call COPIAR\n");
			}
		}
		
		//ASIGNACION
		if(strcmp(t.operador, "=") == 0) {
			pos = buscarIDenTS(t.arg2);
			if(pos!=-1){
				//asignacion struct.
				if(TS[pos].tipo == TIPO_ENTERO) {
					fprintf(assembler, "fild %s\n", t.arg2);
					fprintf(assembler, "fistp %s\n", t.arg1);  
				}else if(TS[pos].tipo == TIPO_REAL){
					fprintf(assembler, "fld %s\n", t.arg2);  
					fprintf(assembler, "fstp %s\n", t.arg1); 
				}else if(TS[pos].tipo == TIPO_STRING){
					fprintf(assembler, "mov si, OFFSET %s\n", t.arg2);
					fprintf(assembler, "mov di, OFFSET __string_aux1\n");
					fprintf(assembler,"call COPIAR\n");
					fprintf(assembler, "mov si, OFFSET __string_aux1\n");
					fprintf(assembler, "mov di, OFFSET %s\n", t.arg1);
					fprintf(assembler, "call COPIAR\n");
				}
			}else {
				// Asignación normal. Dependiendo del tipo llamo a distintas instrucciones.
				if(obtenerTipo(t.arg1) == TIPO_STRING) {
					concatString = false;
					fprintf(assembler, "mov si, OFFSET __string_aux1\n");
					fprintf(assembler, "mov di, OFFSET %s\n", t.arg1);
					fprintf(assembler, "call COPIAR\n");
					cant_string = 0;
				} else if(obtenerTipo(t.arg1) == TIPO_REAL) {
					fprintf(assembler, "fstp %s\n", t.arg1);  
				} else if(obtenerTipo(t.arg1) == TIPO_ENTERO) {
					fprintf(assembler, "fistp %s\n", t.arg1);  
				}
			}
		}
		
		if(strcmp(t.operador, "OUT") == 0) {
			fprintf(assembler, ";muestro por pantalla\n");  
			if( obtenerTipo(t.arg1) == TIPO_STRING) {
				fprintf(assembler, "mov si, OFFSET %s\n", t.arg1);
				fprintf(assembler, "mov di, OFFSET __string_aux1\n");
				fprintf(assembler, "call COPIAR\n");
				fprintf(assembler, "mov dx, OFFSET __string_aux1\n");
				fprintf(assembler, "mov ah, 9\n");
				fprintf(assembler, "int 21h\n");
				fprintf(assembler, "mov dx, OFFSET _NEWLINE\n");
				fprintf(assembler, "mov ah, 9\n");
				fprintf(assembler, "int 21h\n");
			} else if(obtenerTipo(t.arg1) == TIPO_ENTERO) {
				fprintf(assembler,"mov eax, %s\n",t.arg1);
				fprintf(assembler,"call IMPRIMIR_DEC\n");		  
			} else if(obtenerTipo(t.arg1) == TIPO_REAL) {
				fprintf(assembler,"MOV si, OFFSET %s\n", t.arg1);
				fprintf(assembler,"call IMPRIMIR_REAL\n");
			}
		}
		
		if(t.operador[0] == '!') {
			crearSaltoEtiqueta(t.operador+1);
		}

		if(strcmp(t.operador, "DOCASE") == 0) {
			strcpy(aux2,"DOCASE_");
			sprintf(aux1, "%d", ++cont_case);
			strcat(aux2, aux1);
			fprintf(assembler, "%s:\n", aux2);
			apilar(&PI, cont_case);
		}
		if(strcmp(t.operador, "CASE") == 0) {
			strcpy(aux2, "ENDCASE_");
			sprintf(aux1, "%d", tope(PI));
			strcat(aux2, aux1);
			fprintf(assembler,"jmp %s\n",aux2);
		}
		if(strcmp(t.operador, "ENDCASE") == 0) {
			strcpy(aux2, "ENDCASE_");
			sprintf(aux1, "%d", desapilar(&PI));
			strcat(aux2, aux1);
			fprintf(assembler, "%s:\n", aux2);
		}	

		if(strcmp(t.operador, "WHILE") == 0) {
			strcpy(aux2, "WHILE_");
			sprintf(aux1, "%d", ++cont_while);
			strcat(aux2, aux1);
			fprintf(assembler, "%s:\n", aux2);
			apilar(&PI, cont_while);
		}
		if(strcmp(t.operador, "ENDWHILE") == 0) {
			strcpy(aux2, "WHILE_");
			sprintf(aux1, "%d", desapilar(&PI));
			strcat(aux2, aux1);
			fprintf(assembler, "jmp %s\n", aux2);
		}	
		
		if(strcmp(t.operador, "IF") == 0) {
			strcpy(aux2, "IF_");
			sprintf(aux1, "%d", ++cont_if);
			strcat(aux2, aux1);
			fprintf(assembler, "%s:\n", aux2);
			apilar(&PI, cont_if);
		}
		if(strcmp(t.operador, "ELSE") == 0) {
			strcpy(aux2, "FIN_IF_");
			sprintf(aux1, "%d", tope(PI));
			strcat(aux2, aux1);
			fprintf(assembler,"jmp %s\n",aux2);
		}
		if(strcmp(t.operador, "ENDIF") == 0) {
			strcpy(aux2, "FIN_IF_");
			sprintf(aux1, "%d", desapilar(&PI));
			strcat(aux2, aux1);
			fprintf(assembler, "%s:\n", aux2);
		}
		
		if(strcmp(t.operador, "?CMP1") == 0) {
			fprintf(assembler, ";comparo los operandos\n");  
			fprintf(assembler, "fcompp\n");  
			fprintf(assembler, "fstsw __bool_aux1\n");  
			fprintf(assembler, "mov ax, __bool_aux1\n");  
			fprintf(assembler, "fwait\n"); 
			fprintf(assembler, "sahf\n");
			limpiarStack();
		}
		if(strcmp(t.operador, "?CMP2") == 0) {
			fprintf(assembler, ";comparo los otros operandos\n");  
			fprintf(assembler, "fcompp\n");  
			fprintf(assembler, "fstsw __bool_aux2\n");  
			fprintf(assembler, "fwait\n"); 
			fprintf(assembler, "sahf\n");
			limpiarStack();
		}
		
		if(strcmp(t.operador, "EOP")==0)  
			fprintf(assembler,"jmp ESPERA\n");
	}
}

void grabarAssembler() {
	if((assembler = fopen("final.asm", "w")) == NULL) {
		printf("Archivo final.asm: Error de creacion.\n");
		exit(0);
	}
	fprintf(assembler, ".MODEL LARGE\n.386\n.STACK 200h\n");
	fprintf(assembler, ".DATA\n");
	datosasm();  

	fprintf(assembler,".CODE\n");
	codigoasm();
	
	fprintf(assembler,"\nERROR_LIMITE:\n  mov DX, OFFSET _NEWLINE ; agrega new line\n  mov ah, 9\n  int 21h\n  mov dx, OFFSET msgERROR_LIMITE ; imprimir mensaje de error de limite\n  mov ah, 9\n  int 21h\n  mov ah, 1 ;pausa, espera que oprima una tecla\n  int 21h ;AH=1 es el servicio de lectura\n  jmp TERMINAR\n");
	fprintf(assembler,"\nESPERA:\n  mov DX, OFFSET _NEWLINE ; agrega new line\n  mov ah, 9\n  int 21h\n  mov dx, OFFSET msgPRESIONE ; imprimir mensaje de espera\n  mov ah, 9\n  int 21h\n  mov ah, 1 ;pausa, espera que oprima una tecla\n  int 21h ;AH=1 es el servicio de lectura\n  jmp TERMINAR\n");
	fprintf(assembler,"\nTERMINAR:\n  mov ax, 4C00h ;fin de ejecución\n  int 21h\nEND MAIN; fin");
	
	fclose(assembler);
	fclose(intermedio);
}

int main(int argc, char *argv[]) {
	char *nombre;
	
	if(argc == 1) {
		printf("Ingrese nombre de archivo: ");
		nombre = malloc(MAX);
		scanf("%s", nombre);
	} else if(argc == 2) {
		nombre = argv[1];
	} else {
		printf("Demasiados parametros.\n");
		exit(1);
	}

	if((archivoEntrada = fopen(nombre, "rb")) == NULL) {
		printf("Error al abrir el archivo %s", nombre);
		exit(0);
	}

	//esta  linea redirige los printf a un archivo
	//FILE *out = freopen("out", "wb", stdout);

	while(fgetc(archivoEntrada) != EOF) {
		fseek(archivoEntrada, -1, SEEK_CUR);
		yyparse();
	}

	grabarTercetos();
	grabarAssembler();

	mostrarTT();
	mostrarTablaSimbolos();
	printf("---------Compilacion exitosa!!!------------\n");
}

//si no es palabra reservada retorna -1
int verificaReservada(char *c) {
	int i;
	for(i = 0; i < CANT_RESERV; i++) {
		if(strncasecmp(palabrasReservadas[i], c, MAX/2) == 0) {
			return i + 257; //los tokens empiezan en 257
		}
	}
	return -1;
}

int yyerror(char * s) {
	fprintf(stderr, "%s: Linea %d\n", s, linea);
	exit(1);
}

/*Funciones lexicas que utiliza el automata*/
void error() {
	fseek(archivoEntrada, -2, SEEK_CUR);
	printf("Linea: %d. Error lexicografico: se esperaba otro caracter luego de %c\n", linea, fgetc(archivoEntrada));
	exit(1);
}

void eof() {
	tipoToken = 0;
}

void nada() {
}

void iniid() {
	pcToken = cToken;
	*pcToken = caracter;
	longitud = 1;
}

void contid() {
	pcToken++;
	*pcToken = caracter;
	longitud++;
	if(longitud > MAX -1) {
		printf("Linea: %d. Error de longitud en la variable: %s\n", linea, cToken);
		exit(1);
	}
}

void id() {
	pcToken++;
	*pcToken = '\0';
	if((tipoToken = verificaReservada(cToken)) == -1) {
		tipoToken = ID;
		//si el id contiene un punto lo reemplazo por guion bajo
		char *punto = strchr(cToken, '.') ;
		if(punto != NULL) *punto = '_';

		if(bloqueDeclaracion) {
			if((yylval = buscarIDenTS(cToken)) == -1) {
				union sValor valor;
				if(tipoDatoDeclaracion == TIPO_STRING) {
					valor.s = "";
				} else {
					valor.f = 0;
				}
				if(tipoDatoDeclaracion == TIPO_STRUCT) {
					strcpy(structname, cToken);
				}
				yylval = agregarTablaSim(cToken, tipoDatoDeclaracion, valor, 0);
			} else {
				char *punto = strchr(cToken, '_') ;
				if(punto != NULL) *punto = '.';
				printf("Error. La variable %s ya ha sido declarada.\n", cToken);
				exit(0);
			}
		} else {
			if((yylval = buscarIDenTS(cToken)) == -1) {
				//para mostrar bien el valor de la variable struct
				char *caracterPunto = strchr(cToken, '_') ;
				if(caracterPunto != NULL) *punto = '.';
				printf("Error. La variable %s no se encuentra declarada.\n", cToken);
				exit(0);
			}
		}
	}
	posicionTS = yylval;
}

void ininum() {
	pcToken = cToken;
	*pcToken = caracter;
	pcToken++;
	*pcToken = '\0';
}

void contnum() {
	*pcToken = caracter;
	pcToken++;
	*pcToken = '\0';
}

void finentero() {
	char intmax[20];
	sprintf(intmax, "%d", INT_MAX - 1);
	int digitos = strlen(intmax) - 1;
	if(strlen(cToken) > digitos) {
		printf("Linea: %d. Error tamanio constante entera. Maxima cantidad de digitos: %d\n", linea, digitos);
		exit(1);
	}

	valorCteEntera = atoi(cToken);
	if((yylval = buscarEnTablaSimbolos(cToken, TIPO_CTE_ENTERO)) == -1) {
		union sValor valor;
		valor.f = valorCteEntera;
		yylval = agregarTablaSim(cToken, TIPO_CTE_ENTERO, valor, 0);
	}
	posicionTS = yylval;
	tipoToken = CTE_ENTERA;
}

void finreal() {
	char *punto = strchr(cToken, '.');
	char *fin = strchr(cToken, '\0');
	if(punto - cToken > MAX / 2) {
		printf("Linea: %d. Error parte entera constante real. Maxima cantidad de digitos: %d\n", linea, MAX / 2);
		exit(1);
	}
	if(fin - punto - 1 > DBL_DIG) {
		printf("Linea: %d. Error precision constante real. Precision maxima: %d\n", linea, DBL_DIG);
		exit(1);
	}

	valorCteReal = atof(cToken);
	
	//para el nombre reemplazo el punto por un guion bajo
	char nombre[MAX*2];
	strcpy(nombre, cToken);
	*strchr(nombre, '.') = '_';

	if((yylval = buscarEnTablaSimbolos(nombre, TIPO_CTE_REAL)) == -1) {
		union sValor valor;
		valor.f = valorCteReal;
		yylval = agregarTablaSim(nombre, TIPO_CTE_REAL, valor, 0);
	}
	posicionTS = yylval;
	tipoToken = CTE_REAL;
}

void inistring() {
	pcToken = cToken;
	*pcToken = '\0';
}

void contstring() {
	*pcToken = caracter;
	pcToken++;
	*pcToken = '\0';
}

void finstring() {
	pcToken++;
	*pcToken = '\0';
	if(strlen(cToken) > MAX -1) {
		printf("Linea: %d. Error tamanio de cte string: '%s'. El limite son %d caracteres.\n", linea, cToken, MAX-1);
		exit(1);
	}
	//el nombre de la constante string es _s y un numero secuencial de 4 cifras
	char nombre[8];
	sprintf(nombre, "s%04d\0", ++cantCteString);

	if((yylval = buscarStringEnTS(cToken)) == -1) {
		union sValor valor;
		valor.s = cToken;
		yylval = agregarTablaSim(nombre, TIPO_CTE_STRING, valor, strlen(cToken));
	}
	posicionTS = yylval;
	tipoToken = CTE_STR;
	/*	El token de inicio y fin de string es la comilla doble. Como en yylex cada vez que reconozco un token, retrocedo 1 char,
		necesito avanzar 1 char para mantenerme despues de las comillas de fin y q no las tome como el inicio de otro string.*/
	fseek(archivoEntrada, 1, SEEK_CUR);
}

void inibase() {
	pcToken = cToken;
	*pcToken = '\0';
}

void contbase() {
	*pcToken = caracter;
	pcToken++;
	*pcToken = '\0';
}

void finbase() {
	pcToken++;
	*pcToken = '\0';
	if(strlen(cToken) > MAX -1) {
		printf("Linea: %d. Error tamanio de cte base: '%s'. El limite son %d caracteres.\n", linea, cToken, MAX-1);
		exit(1);
	}

    char *coma = strchr(cToken, ',');
    if(cToken == coma || *(coma + 1) == '\0') {
        printf("Linea: %d. Error en el formato de la constante en otra base.\n", linea);
		exit(1);    
    }

	int base = atoi(coma + 1);
	if(base != 2 && base != 16) {
		printf("Linea: %d. Error en la base. Sólo pueden convertirse numeros en base 2 o 16.\n", linea);
		exit(1);
	}

    *coma = '\0';
    char* endptr;
    valorCteEntera = strtol(cToken, &endptr, base);
	if(valorCteEntera == 0 && atoi(cToken) != 0 || *endptr != '\0') {
		printf("Linea: %d. No es posible convertir '%s' a base %d.\n", linea, cToken, base);
		exit(1);
	}

    char nombre[MAX*2];
	sprintf(nombre, "%d", (int) valorCteEntera);

	if((yylval = buscarEnTablaSimbolos(nombre, TIPO_CTE_ENTERO)) == -1) {
		union sValor valor;
		valor.f = valorCteEntera;
		yylval = agregarTablaSim(nombre, TIPO_CTE_ENTERO, valor, 0);
	}
	posicionTS = yylval;
	tipoToken = CTE_ENTERA;
	/*	El token de fin de constante en otra base es la llave de cierre. Como en yylex cada vez que reconozco un token, retrocedo 1 char,
		necesito avanzar 1 char para mantenerme despues de la llave*/
	fseek(archivoEntrada, 1, SEEK_CUR);
}

void suma() {
	tipoToken = OP_SUMA;
}

void resta() {
	tipoToken = OP_RESTA;
}

void producto() {
	tipoToken = OP_MUL;
}

void division() {
	tipoToken = OP_DIV;
}

void mayor() {
	tipoToken = MAYOR;
}

void mayorigual() {
	tipoToken = MAYOR_IGUAL;
}

void menor() {
	tipoToken = MENOR;
}

void menorigual() {
	tipoToken = MENOR_IGUAL;
}

void asig() {
	tipoToken = OP_ASIG;
}

void igual() {
	tipoToken = IGUAL;
}

void distinto() {
	tipoToken = DISTINTO;
}

void coma() {
	tipoToken = COMA;
}

void puntocoma() {
	tipoToken = PUNTO_COMA;
}

void dospuntos() {
	tipoToken = DOS_PUNTOS;
}

void abrepar() {
	tipoToken = ABRE_PAR;
}

void cierrapar() {
	tipoToken = CIERRA_PAR;
}

void abrecor() {
	tipoToken = ABRE_COR;
}

void cierracor() {
	tipoToken = CIERRA_COR;
}
